const { Socket } = require('dgram')
var net = require('net')
var ACTIONS = require('./actions')
const { Log } = require('./logger')

class MainServer {
    constructor(localPort) {
        this.localPort = localPort
        this.tcpServer = null
        this.nodeSocketMap = new Map()
        MainServer.instance = this
    }

    start() {
        this.tcpServer = net.createServer((nodesocket) => {
            // new connection from node
            Log.info("nodeclient connecting ...")
            Log.info("local %s, %s", nodesocket.localAddress, nodesocket.localPort)
            Log.info("remote %s, %s", nodesocket.remoteAddress, nodesocket.remotePort)

            nodesocket.on('close', (had_error) => {
                Log.info('nodescoket closed [%s]', nodesocket.nodeName)
            })
            nodesocket.on('data', (data) => {
                let actions = data.toString()
                Log.info("<< %s [%s]", nodesocket.nodeName, actions.replace("\r\n", ";"))
                let acts = actions.split('\r\n');
                acts.filter((it) => { return !(it == '') }).forEach((item) => {
                    try {
                        let act = JSON.parse(item)
                        switch (act.Action) {
                            // 注册
                            case ACTIONS.REG_STR:
                                var ni = this.nodeSocketMap.get(act.name)
                                if (ni && ni.socket) {
                                    ni.socket.destroy()
                                }
                                nodesocket.nodeName = act.name
                                this.nodeSocketMap.set(act.name, { socket: nodesocket, name: act.name, alive: true, time: new Date() })
                                break;
                            // 心跳
                            case ACTIONS.HBEAT_STR:
                                var ni = this.nodeSocketMap.get(act.name)
                                if (ni) {
                                    ni.alive = true;
                                    ni.time = new Date()
                                }
                                break;
                            default:
                                ;
                        }
                    } catch (err) {
                        Log.error("nodesocket has err:", err)
                        let ni = this.nodeSocketMap.get(nodesocket.nodeName)
                        if (ni) {
                            ni.alive = false
                            ni.time = new Date()
                            ni.socket = null
                        }
                        nodesocket.destroy()
                    }
                })
            })
            nodesocket.on('error', (err) => {
                Log.error("nodesocket on error:", err)
                let ni = this.nodeSocketMap.get(nodesocket.nodeName)
                if (ni) {
                    ni.alive = false
                    ni.time = new Date()
                    ni.socket = null
                }
                nodesocket.destroy()
            })
        })

        this.tcpServer.on('error', (error) => {
            Log.error("mainServer tcpServer on error:", error)
        })

        this.tcpServer.listen(this.localPort, () => {
            Log.info("mainserver tcpServer listen on port : %s", this.localPort)
        })
    }

    send(nodeName, action) {
        let ni = this.nodeSocketMap.get(nodeName)
        if (ni && ni.alive) {
            try {
                ni.socket.write(JSON.stringify(action) + "\r\n")
                return true
            } catch (error) {
                Log.error("main socket send error", error)
                return false
            }
        } else {
            Log.error("mainServer send failed, node [%s] not connected or alived  [%s]", nodeName, JSON.stringify(action))
            return false
        }
    }
}



module.exports = MainServer